<!doctype html>

<html>
<head>
  <link rel="shortcut icon" href="static/images/favicon.ico" type="image/x-icon">
  <title>query.js (Closure Library API Documentation - JavaScript)</title>
  <link rel="stylesheet" href="static/css/base.css">
  <link rel="stylesheet" href="static/css/doc.css">
  <link rel="stylesheet" href="static/css/sidetree.css">
  <link rel="stylesheet" href="static/css/prettify.css">

  <script>
     var _staticFilePath = "static/";
     var _typeTreeName = "goog";
     var _fileTreeName = "Source";
  </script>

  <script src="static/js/doc.js">
  </script>


  <meta charset="utf8">
</head>

<body onload="grokdoc.onLoad();">

<div id="header">
  <div class="g-section g-tpl-50-50 g-split">
    <div class="g-unit g-first">
      <a id="logo" href="index.html">Closure Library API Documentation</a>
    </div>

    <div class="g-unit">
      <div class="g-c">
        <strong>Go to class or file:</strong>
        <input type="text" id="ac">
      </div>
    </div>
  </div>
</div>

<div class="clear"></div>

<h2><a href="closure_third_party_closure_goog_dojo_dom_query.js.html">query.js</a></h2>

<pre class="prettyprint lang-js">
<a name="line1"></a>// Copyright 2005-2009, The Dojo Foundation
<a name="line2"></a>// Modifications Copyright 2008 The Closure Library Authors.
<a name="line3"></a>// All Rights Reserved.
<a name="line4"></a>
<a name="line5"></a>/**
<a name="line6"></a> * @license Portions of this code are from the Dojo Toolkit, received by
<a name="line7"></a> * The Closure Library Authors under the BSD license. All other code is
<a name="line8"></a> * Copyright 2005-2009 The Closure Library Authors. All Rights Reserved.
<a name="line9"></a>
<a name="line10"></a>The &quot;New&quot; BSD License:
<a name="line11"></a>
<a name="line12"></a>Copyright (c) 2005-2009, The Dojo Foundation
<a name="line13"></a>All rights reserved.
<a name="line14"></a>
<a name="line15"></a>Redistribution and use in source and binary forms, with or without
<a name="line16"></a>modification, are permitted provided that the following conditions are met:
<a name="line17"></a>
<a name="line18"></a>  * Redistributions of source code must retain the above copyright notice, this
<a name="line19"></a>    list of conditions and the following disclaimer.
<a name="line20"></a>  * Redistributions in binary form must reproduce the above copyright notice,
<a name="line21"></a>    this list of conditions and the following disclaimer in the documentation
<a name="line22"></a>    and/or other materials provided with the distribution.
<a name="line23"></a>  * Neither the name of the Dojo Foundation nor the names of its contributors
<a name="line24"></a>    may be used to endorse or promote products derived from this software
<a name="line25"></a>    without specific prior written permission.
<a name="line26"></a>
<a name="line27"></a>THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot; AND
<a name="line28"></a>ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
<a name="line29"></a>WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
<a name="line30"></a>DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
<a name="line31"></a>FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
<a name="line32"></a>DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
<a name="line33"></a>SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
<a name="line34"></a>CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
<a name="line35"></a>OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
<a name="line36"></a>OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<a name="line37"></a>*/
<a name="line38"></a>
<a name="line39"></a>/**
<a name="line40"></a> * @fileoverview This code was ported from the Dojo Toolkit
<a name="line41"></a>   http://dojotoolkit.org and modified slightly for Closure.
<a name="line42"></a> *
<a name="line43"></a> *  goog.dom.query is a relatively full-featured CSS3 query function. It is
<a name="line44"></a> *  designed to take any valid CSS3 selector and return the nodes matching
<a name="line45"></a> *  the selector. To do this quickly, it processes queries in several
<a name="line46"></a> *  steps, applying caching where profitable.
<a name="line47"></a> *    The steps (roughly in reverse order of the way they appear in the code):
<a name="line48"></a> *    1.) check to see if we already have a &quot;query dispatcher&quot;
<a name="line49"></a> *      - if so, use that with the given parameterization. Skip to step 4.
<a name="line50"></a> *    2.) attempt to determine which branch to dispatch the query to:
<a name="line51"></a> *      - JS (optimized DOM iteration)
<a name="line52"></a> *      - native (FF3.1, Safari 3.2+, Chrome, some IE 8 doctypes). If native,
<a name="line53"></a> *        skip to step 4, using a stub dispatcher for QSA queries.
<a name="line54"></a> *    3.) tokenize and convert to executable &quot;query dispatcher&quot;
<a name="line55"></a> *        assembled as a chain of &quot;yes/no&quot; test functions pertaining to
<a name="line56"></a> *        a section of a simple query statement (&quot;.blah:nth-child(odd)&quot;
<a name="line57"></a> *        but not &quot;div div&quot;, which is 2 simple statements).
<a name="line58"></a> *    4.) the resulting query dispatcher is called in the passed scope
<a name="line59"></a> *        (by default the top-level document)
<a name="line60"></a> *      - for DOM queries, this results in a recursive, top-down
<a name="line61"></a> *        evaluation of nodes based on each simple query section
<a name="line62"></a> *      - querySelectorAll is used instead of DOM where possible. If a query
<a name="line63"></a> *        fails in this mode, it is re-run against the DOM evaluator and all
<a name="line64"></a> *        future queries using the same selector evaluate against the DOM branch
<a name="line65"></a> *        too.
<a name="line66"></a> *    5.) matched nodes are pruned to ensure they are unique
<a name="line67"></a> */
<a name="line68"></a>
<a name="line69"></a>goog.provide(&#39;goog.dom.query&#39;);
<a name="line70"></a>
<a name="line71"></a>goog.require(&#39;goog.array&#39;);
<a name="line72"></a>goog.require(&#39;goog.dom&#39;);
<a name="line73"></a>goog.require(&#39;goog.functions&#39;);
<a name="line74"></a>goog.require(&#39;goog.string&#39;);
<a name="line75"></a>goog.require(&#39;goog.userAgent&#39;);
<a name="line76"></a>
<a name="line77"></a>  /**
<a name="line78"></a>   * Returns nodes which match the given CSS3 selector, searching the
<a name="line79"></a>   * entire document by default but optionally taking a node to scope
<a name="line80"></a>   * the search by.
<a name="line81"></a>   *
<a name="line82"></a>   * dojo.query() is the swiss army knife of DOM node manipulation in
<a name="line83"></a>   * Dojo. Much like Prototype&#39;s &quot;$$&quot; (bling-bling) function or JQuery&#39;s
<a name="line84"></a>   * &quot;$&quot; function, dojo.query provides robust, high-performance
<a name="line85"></a>   * CSS-based node selector support with the option of scoping searches
<a name="line86"></a>   * to a particular sub-tree of a document.
<a name="line87"></a>   *
<a name="line88"></a>   * Supported Selectors:
<a name="line89"></a>   * --------------------
<a name="line90"></a>   *
<a name="line91"></a>   * dojo.query() supports a rich set of CSS3 selectors, including:
<a name="line92"></a>   *
<a name="line93"></a>   *   * class selectors (e.g., `.foo`)
<a name="line94"></a>   *   * node type selectors like `span`
<a name="line95"></a>   *   * ` ` descendant selectors
<a name="line96"></a>   *   * `&gt;` child element selectors
<a name="line97"></a>   *   * `#foo` style ID selectors
<a name="line98"></a>   *   * `*` universal selector
<a name="line99"></a>   *   * `~`, the immediately preceded-by sibling selector
<a name="line100"></a>   *   * `+`, the preceded-by sibling selector
<a name="line101"></a>   *   * attribute queries:
<a name="line102"></a>   *   |  * `[foo]` attribute presence selector
<a name="line103"></a>   *   |  * `[foo=&#39;bar&#39;]` attribute value exact match
<a name="line104"></a>   *   |  * `[foo~=&#39;bar&#39;]` attribute value list item match
<a name="line105"></a>   *   |  * `[foo^=&#39;bar&#39;]` attribute start match
<a name="line106"></a>   *   |  * `[foo$=&#39;bar&#39;]` attribute end match
<a name="line107"></a>   *   |  * `[foo*=&#39;bar&#39;]` attribute substring match
<a name="line108"></a>   *   * `:first-child`, `:last-child` positional selectors
<a name="line109"></a>   *   * `:empty` content empty selector
<a name="line110"></a>   *   * `:empty` content empty selector
<a name="line111"></a>   *   * `:nth-child(n)`, `:nth-child(2n+1)` style positional calculations
<a name="line112"></a>   *   * `:nth-child(even)`, `:nth-child(odd)` positional selectors
<a name="line113"></a>   *   * `:not(...)` negation pseudo selectors
<a name="line114"></a>   *
<a name="line115"></a>   * Any legal combination of these selectors will work with
<a name="line116"></a>   * `dojo.query()`, including compound selectors (&quot;,&quot; delimited).
<a name="line117"></a>   * Very complex and useful searches can be constructed with this
<a name="line118"></a>   * palette of selectors.
<a name="line119"></a>   *
<a name="line120"></a>   * Unsupported Selectors:
<a name="line121"></a>   * ----------------------
<a name="line122"></a>   *
<a name="line123"></a>   * While dojo.query handles many CSS3 selectors, some fall outside of
<a name="line124"></a>   * what&#39;s reasonable for a programmatic node querying engine to
<a name="line125"></a>   * handle. Currently unsupported selectors include:
<a name="line126"></a>   *
<a name="line127"></a>   *   * namespace-differentiated selectors of any form
<a name="line128"></a>   *   * all `::` pseudo-element selectors
<a name="line129"></a>   *   * certain pseudo-selectors which don&#39;t get a lot of day-to-day use:
<a name="line130"></a>   *   |  * `:root`, `:lang()`, `:target`, `:focus`
<a name="line131"></a>   *   * all visual and state selectors:
<a name="line132"></a>   *   |  * `:root`, `:active`, `:hover`, `:visited`, `:link`,
<a name="line133"></a>   *       `:enabled`, `:disabled`, `:checked`
<a name="line134"></a>   *   * `:*-of-type` pseudo selectors
<a name="line135"></a>   *
<a name="line136"></a>   * dojo.query and XML Documents:
<a name="line137"></a>   * -----------------------------
<a name="line138"></a>   *
<a name="line139"></a>   * `dojo.query` currently only supports searching XML documents
<a name="line140"></a>   * whose tags and attributes are 100% lower-case. This is a known
<a name="line141"></a>   * limitation and will [be addressed soon]
<a name="line142"></a>   * (http://trac.dojotoolkit.org/ticket/3866)
<a name="line143"></a>   *
<a name="line144"></a>   * Non-selector Queries:
<a name="line145"></a>   * ---------------------
<a name="line146"></a>   *
<a name="line147"></a>   * If something other than a String is passed for the query,
<a name="line148"></a>   * `dojo.query` will return a new array constructed from
<a name="line149"></a>   * that parameter alone and all further processing will stop. This
<a name="line150"></a>   * means that if you have a reference to a node or array or nodes, you
<a name="line151"></a>   * can quickly construct a new array of nodes from the original by
<a name="line152"></a>   * calling `dojo.query(node)` or `dojo.query(array)`.
<a name="line153"></a>   *
<a name="line154"></a>   * example:
<a name="line155"></a>   *   search the entire document for elements with the class &quot;foo&quot;:
<a name="line156"></a>   * |  dojo.query(&quot;.foo&quot;);
<a name="line157"></a>   *   these elements will match:
<a name="line158"></a>   * |  &lt;span class=&quot;foo&quot;&gt;&lt;/span&gt;
<a name="line159"></a>   * |  &lt;span class=&quot;foo bar&quot;&gt;&lt;/span&gt;
<a name="line160"></a>   * |  &lt;p class=&quot;thud foo&quot;&gt;&lt;/p&gt;
<a name="line161"></a>   * example:
<a name="line162"></a>   *   search the entire document for elements with the classes &quot;foo&quot; *and*
<a name="line163"></a>   *   &quot;bar&quot;:
<a name="line164"></a>   * |  dojo.query(&quot;.foo.bar&quot;);
<a name="line165"></a>   *   these elements will match:
<a name="line166"></a>   * |  &lt;span class=&quot;foo bar&quot;&gt;&lt;/span&gt;
<a name="line167"></a>   *   while these will not:
<a name="line168"></a>   * |  &lt;span class=&quot;foo&quot;&gt;&lt;/span&gt;
<a name="line169"></a>   * |  &lt;p class=&quot;thud foo&quot;&gt;&lt;/p&gt;
<a name="line170"></a>   * example:
<a name="line171"></a>   *   find `&lt;span&gt;` elements which are descendants of paragraphs and
<a name="line172"></a>   *   which have a &quot;highlighted&quot; class:
<a name="line173"></a>   * |  dojo.query(&quot;p span.highlighted&quot;);
<a name="line174"></a>   *   the innermost span in this fragment matches:
<a name="line175"></a>   * |  &lt;p class=&quot;foo&quot;&gt;
<a name="line176"></a>   * |    &lt;span&gt;...
<a name="line177"></a>   * |      &lt;span class=&quot;highlighted foo bar&quot;&gt;...&lt;/span&gt;
<a name="line178"></a>   * |    &lt;/span&gt;
<a name="line179"></a>   * |  &lt;/p&gt;
<a name="line180"></a>   * example:
<a name="line181"></a>   *   find all odd table rows inside of the table
<a name="line182"></a>   *   `#tabular_data`, using the `&gt;` (direct child) selector to avoid
<a name="line183"></a>   *   affecting any nested tables:
<a name="line184"></a>   * |  dojo.query(&quot;#tabular_data &gt; tbody &gt; tr:nth-child(odd)&quot;);
<a name="line185"></a>   *
<a name="line186"></a>   * @param {string|Array} query The CSS3 expression to match against.
<a name="line187"></a>   *     For details on the syntax of CSS3 selectors, see
<a name="line188"></a>   *     http://www.w3.org/TR/css3-selectors/#selectors.
<a name="line189"></a>   * @param {(string|Node)=} opt_root A Node (or node id) to scope the search
<a name="line190"></a>   *     from (optional).
<a name="line191"></a>   * @return { {length: number} } The elements that matched the query.
<a name="line192"></a>   */
<a name="line193"></a>goog.dom.query = (function() {
<a name="line194"></a>  ////////////////////////////////////////////////////////////////////////
<a name="line195"></a>  // Global utilities
<a name="line196"></a>  ////////////////////////////////////////////////////////////////////////
<a name="line197"></a>
<a name="line198"></a>  var cssCaseBug = (goog.userAgent.WEBKIT &amp;&amp;
<a name="line199"></a>                     ((goog.dom.getDocument().compatMode) == &#39;BackCompat&#39;)
<a name="line200"></a>                   );
<a name="line201"></a>
<a name="line202"></a>  // On browsers that support the &quot;children&quot; collection we can avoid a lot of
<a name="line203"></a>  // iteration on chaff (non-element) nodes.
<a name="line204"></a>  var childNodesName = !!goog.dom.getDocument().firstChild[&#39;children&#39;] ?
<a name="line205"></a>                          &#39;children&#39; :
<a name="line206"></a>                          &#39;childNodes&#39;;
<a name="line207"></a>
<a name="line208"></a>  var specials = &#39;&gt;~+&#39;;
<a name="line209"></a>
<a name="line210"></a>  // Global thunk to determine whether we should treat the current query as
<a name="line211"></a>  // case sensitive or not. This switch is flipped by the query evaluator based
<a name="line212"></a>  // on the document passed as the context to search.
<a name="line213"></a>  var caseSensitive = false;
<a name="line214"></a>
<a name="line215"></a>
<a name="line216"></a>  ////////////////////////////////////////////////////////////////////////
<a name="line217"></a>  // Tokenizer
<a name="line218"></a>  ////////////////////////////////////////////////////////////////////////
<a name="line219"></a>
<a name="line220"></a>  var getQueryParts = function(query) {
<a name="line221"></a>    //  summary:
<a name="line222"></a>    //    state machine for query tokenization
<a name="line223"></a>    //  description:
<a name="line224"></a>    //    instead of using a brittle and slow regex-based CSS parser,
<a name="line225"></a>    //    dojo.query implements an AST-style query representation. This
<a name="line226"></a>    //    representation is only generated once per query. For example,
<a name="line227"></a>    //    the same query run multiple times or under different root nodes
<a name="line228"></a>    //    does not re-parse the selector expression but instead uses the
<a name="line229"></a>    //    cached data structure. The state machine implemented here
<a name="line230"></a>    //    terminates on the last &quot; &quot; (space) character and returns an
<a name="line231"></a>    //    ordered array of query component structures (or &quot;parts&quot;). Each
<a name="line232"></a>    //    part represents an operator or a simple CSS filtering
<a name="line233"></a>    //    expression. The structure for parts is documented in the code
<a name="line234"></a>    //    below.
<a name="line235"></a>
<a name="line236"></a>
<a name="line237"></a>    // NOTE:
<a name="line238"></a>    //    this code is designed to run fast and compress well. Sacrifices
<a name="line239"></a>    //    to readability and maintainability have been made.
<a name="line240"></a>    if (specials.indexOf(query.slice(-1)) &gt;= 0) {
<a name="line241"></a>      // If we end with a &quot;&gt;&quot;, &quot;+&quot;, or &quot;~&quot;, that means we&#39;re implicitly
<a name="line242"></a>      // searching all children, so make it explicit.
<a name="line243"></a>      query += &#39; * &#39;
<a name="line244"></a>    } else {
<a name="line245"></a>      // if you have not provided a terminator, one will be provided for
<a name="line246"></a>      // you...
<a name="line247"></a>      query += &#39; &#39;;
<a name="line248"></a>    }
<a name="line249"></a>
<a name="line250"></a>    var ts = function(/*Integer*/ s, /*Integer*/ e) {
<a name="line251"></a>      // trim and slice.
<a name="line252"></a>
<a name="line253"></a>      // take an index to start a string slice from and an end position
<a name="line254"></a>      // and return a trimmed copy of that sub-string
<a name="line255"></a>      return goog.string.trim(query.slice(s, e));
<a name="line256"></a>    };
<a name="line257"></a>
<a name="line258"></a>    // The overall data graph of the full query, as represented by queryPart
<a name="line259"></a>    // objects.
<a name="line260"></a>    var queryParts = [];
<a name="line261"></a>
<a name="line262"></a>
<a name="line263"></a>    // state keeping vars
<a name="line264"></a>    var inBrackets = -1,
<a name="line265"></a>        inParens = -1,
<a name="line266"></a>        inMatchFor = -1,
<a name="line267"></a>        inPseudo = -1,
<a name="line268"></a>        inClass = -1,
<a name="line269"></a>        inId = -1,
<a name="line270"></a>        inTag = -1,
<a name="line271"></a>        lc = &#39;&#39;,
<a name="line272"></a>        cc = &#39;&#39;,
<a name="line273"></a>        pStart;
<a name="line274"></a>
<a name="line275"></a>    // iteration vars
<a name="line276"></a>    var x = 0, // index in the query
<a name="line277"></a>        ql = query.length,
<a name="line278"></a>        currentPart = null, // data structure representing the entire clause
<a name="line279"></a>        cp = null; // the current pseudo or attr matcher
<a name="line280"></a>
<a name="line281"></a>    // several temporary variables are assigned to this structure during a
<a name="line282"></a>    // potential sub-expression match:
<a name="line283"></a>    //    attr:
<a name="line284"></a>    //      a string representing the current full attribute match in a
<a name="line285"></a>    //      bracket expression
<a name="line286"></a>    //    type:
<a name="line287"></a>    //      if there&#39;s an operator in a bracket expression, this is
<a name="line288"></a>    //      used to keep track of it
<a name="line289"></a>    //    value:
<a name="line290"></a>    //      the internals of parenthetical expression for a pseudo. for
<a name="line291"></a>    //      :nth-child(2n+1), value might be &#39;2n+1&#39;
<a name="line292"></a>
<a name="line293"></a>    var endTag = function() {
<a name="line294"></a>      // called when the tokenizer hits the end of a particular tag name.
<a name="line295"></a>      // Re-sets state variables for tag matching and sets up the matcher
<a name="line296"></a>      // to handle the next type of token (tag or operator).
<a name="line297"></a>      if (inTag &gt;= 0) {
<a name="line298"></a>        var tv = (inTag == x) ? null : ts(inTag, x);
<a name="line299"></a>        if (specials.indexOf(tv) &lt; 0) {
<a name="line300"></a>          currentPart.tag = tv;
<a name="line301"></a>        } else {
<a name="line302"></a>          currentPart.oper = tv;
<a name="line303"></a>        }
<a name="line304"></a>        inTag = -1;
<a name="line305"></a>      }
<a name="line306"></a>    };
<a name="line307"></a>
<a name="line308"></a>    var endId = function() {
<a name="line309"></a>      // Called when the tokenizer might be at the end of an ID portion of a
<a name="line310"></a>      // match.
<a name="line311"></a>      if (inId &gt;= 0) {
<a name="line312"></a>        currentPart.id = ts(inId, x).replace(/\\/g, &#39;&#39;);
<a name="line313"></a>        inId = -1;
<a name="line314"></a>      }
<a name="line315"></a>    };
<a name="line316"></a>
<a name="line317"></a>    var endClass = function() {
<a name="line318"></a>      // Called when the tokenizer might be at the end of a class name
<a name="line319"></a>      // match. CSS allows for multiple classes, so we augment the
<a name="line320"></a>      // current item with another class in its list.
<a name="line321"></a>      if (inClass &gt;= 0) {
<a name="line322"></a>        currentPart.classes.push(ts(inClass + 1, x).replace(/\\/g, &#39;&#39;));
<a name="line323"></a>        inClass = -1;
<a name="line324"></a>      }
<a name="line325"></a>    };
<a name="line326"></a>
<a name="line327"></a>    var endAll = function() {
<a name="line328"></a>      // at the end of a simple fragment, so wall off the matches
<a name="line329"></a>      endId(); endTag(); endClass();
<a name="line330"></a>    };
<a name="line331"></a>
<a name="line332"></a>    var endPart = function() {
<a name="line333"></a>      endAll();
<a name="line334"></a>      if (inPseudo &gt;= 0) {
<a name="line335"></a>        currentPart.pseudos.push({ name: ts(inPseudo + 1, x) });
<a name="line336"></a>      }
<a name="line337"></a>      // Hint to the selector engine to tell it whether or not it
<a name="line338"></a>      // needs to do any iteration. Many simple selectors don&#39;t, and
<a name="line339"></a>      // we can avoid significant construction-time work by advising
<a name="line340"></a>      // the system to skip them.
<a name="line341"></a>      currentPart.loops = currentPart.pseudos.length ||
<a name="line342"></a>                          currentPart.attrs.length ||
<a name="line343"></a>                          currentPart.classes.length;
<a name="line344"></a>
<a name="line345"></a>      // save the full expression as a string
<a name="line346"></a>      currentPart.oquery = currentPart.query = ts(pStart, x);
<a name="line347"></a>
<a name="line348"></a>
<a name="line349"></a>      // otag/tag are hints to suggest to the system whether or not
<a name="line350"></a>      // it&#39;s an operator or a tag. We save a copy of otag since the
<a name="line351"></a>      // tag name is cast to upper-case in regular HTML matches. The
<a name="line352"></a>      // system has a global switch to figure out if the current
<a name="line353"></a>      // expression needs to be case sensitive or not and it will use
<a name="line354"></a>      // otag or tag accordingly
<a name="line355"></a>      currentPart.otag = currentPart.tag = (currentPart.oper) ?
<a name="line356"></a>                                                     null :
<a name="line357"></a>                                                     (currentPart.tag || &#39;*&#39;);
<a name="line358"></a>
<a name="line359"></a>      if (currentPart.tag) {
<a name="line360"></a>        // if we&#39;re in a case-insensitive HTML doc, we likely want
<a name="line361"></a>        // the toUpperCase when matching on element.tagName. If we
<a name="line362"></a>        // do it here, we can skip the string op per node
<a name="line363"></a>        // comparison
<a name="line364"></a>        currentPart.tag = currentPart.tag.toUpperCase();
<a name="line365"></a>      }
<a name="line366"></a>
<a name="line367"></a>      // add the part to the list
<a name="line368"></a>      if (queryParts.length &amp;&amp; (queryParts[queryParts.length - 1].oper)) {
<a name="line369"></a>        // operators are always infix, so we remove them from the
<a name="line370"></a>        // list and attach them to the next match. The evaluator is
<a name="line371"></a>        // responsible for sorting out how to handle them.
<a name="line372"></a>        currentPart.infixOper = queryParts.pop();
<a name="line373"></a>        currentPart.query = currentPart.infixOper.query + &#39; &#39; +
<a name="line374"></a>            currentPart.query;
<a name="line375"></a>      }
<a name="line376"></a>      queryParts.push(currentPart);
<a name="line377"></a>
<a name="line378"></a>      currentPart = null;
<a name="line379"></a>    }
<a name="line380"></a>
<a name="line381"></a>    // iterate over the query, character by character, building up a
<a name="line382"></a>    // list of query part objects
<a name="line383"></a>    for (; lc = cc, cc = query.charAt(x), x &lt; ql; x++) {
<a name="line384"></a>      //    cc: the current character in the match
<a name="line385"></a>      //    lc: the last character (if any)
<a name="line386"></a>
<a name="line387"></a>      // someone is trying to escape something, so don&#39;t try to match any
<a name="line388"></a>      // fragments. We assume we&#39;re inside a literal.
<a name="line389"></a>      if (lc == &#39;\\&#39;) {
<a name="line390"></a>        continue;
<a name="line391"></a>      }
<a name="line392"></a>      if (!currentPart) { // a part was just ended or none has yet been created
<a name="line393"></a>        // NOTE: I hate all this alloc, but it&#39;s shorter than writing tons of
<a name="line394"></a>        // if&#39;s
<a name="line395"></a>        pStart = x;
<a name="line396"></a>        //  rules describe full CSS sub-expressions, like:
<a name="line397"></a>        //    #someId
<a name="line398"></a>        //    .className:first-child
<a name="line399"></a>        //  but not:
<a name="line400"></a>        //    thinger &gt; div.howdy[type=thinger]
<a name="line401"></a>        //  the individual components of the previous query would be
<a name="line402"></a>        //  split into 3 parts that would be represented a structure
<a name="line403"></a>        //  like:
<a name="line404"></a>        //    [
<a name="line405"></a>        //      {
<a name="line406"></a>        //        query: &#39;thinger&#39;,
<a name="line407"></a>        //        tag: &#39;thinger&#39;,
<a name="line408"></a>        //      },
<a name="line409"></a>        //      {
<a name="line410"></a>        //        query: &#39;div.howdy[type=thinger]&#39;,
<a name="line411"></a>        //        classes: [&#39;howdy&#39;],
<a name="line412"></a>        //        infixOper: {
<a name="line413"></a>        //          query: &#39;&gt;&#39;,
<a name="line414"></a>        //          oper: &#39;&gt;&#39;,
<a name="line415"></a>        //        }
<a name="line416"></a>        //      },
<a name="line417"></a>        //    ]
<a name="line418"></a>        currentPart = {
<a name="line419"></a>          query: null, // the full text of the part&#39;s rule
<a name="line420"></a>          pseudos: [], // CSS supports multiple pseudo-class matches in a single
<a name="line421"></a>              // rule
<a name="line422"></a>          attrs: [],  // CSS supports multi-attribute match, so we need an array
<a name="line423"></a>          classes: [], // class matches may be additive,
<a name="line424"></a>              // e.g.: .thinger.blah.howdy
<a name="line425"></a>          tag: null,  // only one tag...
<a name="line426"></a>          oper: null, // ...or operator per component. Note that these wind up
<a name="line427"></a>              // being exclusive.
<a name="line428"></a>          id: null,   // the id component of a rule
<a name="line429"></a>          getTag: function() {
<a name="line430"></a>            return (caseSensitive) ? this.otag : this.tag;
<a name="line431"></a>          }
<a name="line432"></a>        };
<a name="line433"></a>
<a name="line434"></a>        // if we don&#39;t have a part, we assume we&#39;re going to start at
<a name="line435"></a>        // the beginning of a match, which should be a tag name. This
<a name="line436"></a>        // might fault a little later on, but we detect that and this
<a name="line437"></a>        // iteration will still be fine.
<a name="line438"></a>        inTag = x;
<a name="line439"></a>      }
<a name="line440"></a>
<a name="line441"></a>      if (inBrackets &gt;= 0) {
<a name="line442"></a>        // look for a the close first
<a name="line443"></a>        if (cc == &#39;]&#39;) { // if we&#39;re in a [...] clause and we end, do assignment
<a name="line444"></a>          if (!cp.attr) {
<a name="line445"></a>            // no attribute match was previously begun, so we
<a name="line446"></a>            // assume this is an attribute existence match in the
<a name="line447"></a>            // form of [someAttributeName]
<a name="line448"></a>            cp.attr = ts(inBrackets + 1, x);
<a name="line449"></a>          } else {
<a name="line450"></a>            // we had an attribute already, so we know that we&#39;re
<a name="line451"></a>            // matching some sort of value, as in [attrName=howdy]
<a name="line452"></a>            cp.matchFor = ts((inMatchFor || inBrackets + 1), x);
<a name="line453"></a>          }
<a name="line454"></a>          var cmf = cp.matchFor;
<a name="line455"></a>          if (cmf) {
<a name="line456"></a>            // try to strip quotes from the matchFor value. We want
<a name="line457"></a>            // [attrName=howdy] to match the same
<a name="line458"></a>            //  as [attrName = &#39;howdy&#39; ]
<a name="line459"></a>            if ((cmf.charAt(0) == &#39;&quot;&#39;) || (cmf.charAt(0) == &quot;&#39;&quot;)) {
<a name="line460"></a>              cp.matchFor = cmf.slice(1, -1);
<a name="line461"></a>            }
<a name="line462"></a>          }
<a name="line463"></a>          // end the attribute by adding it to the list of attributes.
<a name="line464"></a>          currentPart.attrs.push(cp);
<a name="line465"></a>          cp = null; // necessary?
<a name="line466"></a>          inBrackets = inMatchFor = -1;
<a name="line467"></a>        } else if (cc == &#39;=&#39;) {
<a name="line468"></a>          // if the last char was an operator prefix, make sure we
<a name="line469"></a>          // record it along with the &#39;=&#39; operator.
<a name="line470"></a>          var addToCc = (&#39;|~^$*&#39;.indexOf(lc) &gt;= 0) ? lc : &#39;&#39;;
<a name="line471"></a>          cp.type = addToCc + cc;
<a name="line472"></a>          cp.attr = ts(inBrackets + 1, x - addToCc.length);
<a name="line473"></a>          inMatchFor = x + 1;
<a name="line474"></a>        }
<a name="line475"></a>        // now look for other clause parts
<a name="line476"></a>      } else if (inParens &gt;= 0) {
<a name="line477"></a>        // if we&#39;re in a parenthetical expression, we need to figure
<a name="line478"></a>        // out if it&#39;s attached to a pseudo-selector rule like
<a name="line479"></a>        // :nth-child(1)
<a name="line480"></a>        if (cc == &#39;)&#39;) {
<a name="line481"></a>          if (inPseudo &gt;= 0) {
<a name="line482"></a>            cp.value = ts(inParens + 1, x);
<a name="line483"></a>          }
<a name="line484"></a>          inPseudo = inParens = -1;
<a name="line485"></a>        }
<a name="line486"></a>      } else if (cc == &#39;#&#39;) {
<a name="line487"></a>        // start of an ID match
<a name="line488"></a>        endAll();
<a name="line489"></a>        inId = x + 1;
<a name="line490"></a>      } else if (cc == &#39;.&#39;) {
<a name="line491"></a>        // start of a class match
<a name="line492"></a>        endAll();
<a name="line493"></a>        inClass = x;
<a name="line494"></a>      } else if (cc == &#39;:&#39;) {
<a name="line495"></a>        // start of a pseudo-selector match
<a name="line496"></a>        endAll();
<a name="line497"></a>        inPseudo = x;
<a name="line498"></a>      } else if (cc == &#39;[&#39;) {
<a name="line499"></a>        // start of an attribute match.
<a name="line500"></a>        endAll();
<a name="line501"></a>        inBrackets = x;
<a name="line502"></a>        // provide a new structure for the attribute match to fill-in
<a name="line503"></a>        cp = {
<a name="line504"></a>          /*=====
<a name="line505"></a>          attr: null, type: null, matchFor: null
<a name="line506"></a>          =====*/
<a name="line507"></a>        };
<a name="line508"></a>      } else if (cc == &#39;(&#39;) {
<a name="line509"></a>        // we really only care if we&#39;ve entered a parenthetical
<a name="line510"></a>        // expression if we&#39;re already inside a pseudo-selector match
<a name="line511"></a>        if (inPseudo &gt;= 0) {
<a name="line512"></a>          // provide a new structure for the pseudo match to fill-in
<a name="line513"></a>          cp = {
<a name="line514"></a>            name: ts(inPseudo + 1, x),
<a name="line515"></a>            value: null
<a name="line516"></a>          }
<a name="line517"></a>          currentPart.pseudos.push(cp);
<a name="line518"></a>        }
<a name="line519"></a>        inParens = x;
<a name="line520"></a>      } else if (
<a name="line521"></a>        (cc == &#39; &#39;) &amp;&amp;
<a name="line522"></a>        // if it&#39;s a space char and the last char is too, consume the
<a name="line523"></a>        // current one without doing more work
<a name="line524"></a>        (lc != cc)
<a name="line525"></a>      ) {
<a name="line526"></a>        endPart();
<a name="line527"></a>      }
<a name="line528"></a>    }
<a name="line529"></a>    return queryParts;
<a name="line530"></a>  };
<a name="line531"></a>
<a name="line532"></a>
<a name="line533"></a>  ////////////////////////////////////////////////////////////////////////
<a name="line534"></a>  // DOM query infrastructure
<a name="line535"></a>  ////////////////////////////////////////////////////////////////////////
<a name="line536"></a>
<a name="line537"></a>  var agree = function(first, second) {
<a name="line538"></a>    // the basic building block of the yes/no chaining system. agree(f1,
<a name="line539"></a>    // f2) generates a new function which returns the boolean results of
<a name="line540"></a>    // both of the passed functions to a single logical-anded result. If
<a name="line541"></a>    // either are not passed, the other is used exclusively.
<a name="line542"></a>    if (!first) {
<a name="line543"></a>      return second;
<a name="line544"></a>    }
<a name="line545"></a>    if (!second) {
<a name="line546"></a>      return first;
<a name="line547"></a>    }
<a name="line548"></a>
<a name="line549"></a>    return function() {
<a name="line550"></a>      return first.apply(window, arguments) &amp;&amp; second.apply(window, arguments);
<a name="line551"></a>    }
<a name="line552"></a>  };
<a name="line553"></a>
<a name="line554"></a>  /**
<a name="line555"></a>   * @param {Array=} opt_arr
<a name="line556"></a>   */
<a name="line557"></a>  function getArr(i, opt_arr) {
<a name="line558"></a>    // helps us avoid array alloc when we don&#39;t need it
<a name="line559"></a>    var r = opt_arr || [];
<a name="line560"></a>    if (i) {
<a name="line561"></a>      r.push(i);
<a name="line562"></a>    }
<a name="line563"></a>    return r;
<a name="line564"></a>  };
<a name="line565"></a>
<a name="line566"></a>  var isElement = function(n) {
<a name="line567"></a>    return (1 == n.nodeType);
<a name="line568"></a>  };
<a name="line569"></a>
<a name="line570"></a>  // FIXME: need to coalesce getAttr with defaultGetter
<a name="line571"></a>  var blank = &#39;&#39;;
<a name="line572"></a>  var getAttr = function(elem, attr) {
<a name="line573"></a>    if (!elem) {
<a name="line574"></a>      return blank;
<a name="line575"></a>    }
<a name="line576"></a>    if (attr == &#39;class&#39;) {
<a name="line577"></a>      return elem.className || blank;
<a name="line578"></a>    }
<a name="line579"></a>    if (attr == &#39;for&#39;) {
<a name="line580"></a>      return elem.htmlFor || blank;
<a name="line581"></a>    }
<a name="line582"></a>    if (attr == &#39;style&#39;) {
<a name="line583"></a>      return elem.style.cssText || blank;
<a name="line584"></a>    }
<a name="line585"></a>    return (caseSensitive ? elem.getAttribute(attr) :
<a name="line586"></a>        elem.getAttribute(attr, 2)) || blank;
<a name="line587"></a>  };
<a name="line588"></a>
<a name="line589"></a>  var attrs = {
<a name="line590"></a>    &#39;*=&#39;: function(attr, value) {
<a name="line591"></a>      return function(elem) {
<a name="line592"></a>        // E[foo*=&quot;bar&quot;]
<a name="line593"></a>        //    an E element whose &quot;foo&quot; attribute value contains
<a name="line594"></a>        //    the substring &quot;bar&quot;
<a name="line595"></a>        return (getAttr(elem, attr).indexOf(value) &gt;= 0);
<a name="line596"></a>      }
<a name="line597"></a>    },
<a name="line598"></a>    &#39;^=&#39;: function(attr, value) {
<a name="line599"></a>      // E[foo^=&quot;bar&quot;]
<a name="line600"></a>      //    an E element whose &quot;foo&quot; attribute value begins exactly
<a name="line601"></a>      //    with the string &quot;bar&quot;
<a name="line602"></a>      return function(elem) {
<a name="line603"></a>        return (getAttr(elem, attr).indexOf(value) == 0);
<a name="line604"></a>      }
<a name="line605"></a>    },
<a name="line606"></a>    &#39;$=&#39;: function(attr, value) {
<a name="line607"></a>      // E[foo$=&quot;bar&quot;]
<a name="line608"></a>      //    an E element whose &quot;foo&quot; attribute value ends exactly
<a name="line609"></a>      //    with the string &quot;bar&quot;
<a name="line610"></a>      var tval = &#39; &#39; + value;
<a name="line611"></a>      return function(elem) {
<a name="line612"></a>        var ea = &#39; &#39; + getAttr(elem, attr);
<a name="line613"></a>        return (ea.lastIndexOf(value) == (ea.length - value.length));
<a name="line614"></a>      }
<a name="line615"></a>    },
<a name="line616"></a>    &#39;~=&#39;: function(attr, value) {
<a name="line617"></a>      // E[foo~=&quot;bar&quot;]
<a name="line618"></a>      //    an E element whose &quot;foo&quot; attribute value is a list of
<a name="line619"></a>      //    space-separated values, one of which is exactly equal
<a name="line620"></a>      //    to &quot;bar&quot;
<a name="line621"></a>
<a name="line622"></a>      var tval = &#39; &#39; + value + &#39; &#39;;
<a name="line623"></a>      return function(elem) {
<a name="line624"></a>        var ea = &#39; &#39; + getAttr(elem, attr) + &#39; &#39;;
<a name="line625"></a>        return (ea.indexOf(tval) &gt;= 0);
<a name="line626"></a>      }
<a name="line627"></a>    },
<a name="line628"></a>    &#39;|=&#39;: function(attr, value) {
<a name="line629"></a>      // E[hreflang|=&quot;en&quot;]
<a name="line630"></a>      //    an E element whose &quot;hreflang&quot; attribute has a
<a name="line631"></a>      //    hyphen-separated list of values beginning (from the
<a name="line632"></a>      //    left) with &quot;en&quot;
<a name="line633"></a>      value = &#39; &#39; + value;
<a name="line634"></a>      return function(elem) {
<a name="line635"></a>        var ea = &#39; &#39; + getAttr(elem, attr);
<a name="line636"></a>        return (
<a name="line637"></a>          (ea == value) ||
<a name="line638"></a>          (ea.indexOf(value + &#39;-&#39;) == 0)
<a name="line639"></a>        );
<a name="line640"></a>      }
<a name="line641"></a>    },
<a name="line642"></a>    &#39;=&#39;: function(attr, value) {
<a name="line643"></a>      return function(elem) {
<a name="line644"></a>        return (getAttr(elem, attr) == value);
<a name="line645"></a>      }
<a name="line646"></a>    }
<a name="line647"></a>  };
<a name="line648"></a>
<a name="line649"></a>  // avoid testing for node type if we can. Defining this in the negative
<a name="line650"></a>  // here to avoid negation in the fast path.
<a name="line651"></a>  var noNextElementSibling = (
<a name="line652"></a>    typeof goog.dom.getDocument().firstChild.nextElementSibling == &#39;undefined&#39;
<a name="line653"></a>  );
<a name="line654"></a>  var nSibling = !noNextElementSibling ? &#39;nextElementSibling&#39; : &#39;nextSibling&#39;;
<a name="line655"></a>  var pSibling = !noNextElementSibling ?
<a name="line656"></a>                    &#39;previousElementSibling&#39; :
<a name="line657"></a>                    &#39;previousSibling&#39;;
<a name="line658"></a>  var simpleNodeTest = (noNextElementSibling ? isElement : goog.functions.TRUE);
<a name="line659"></a>
<a name="line660"></a>  var _lookLeft = function(node) {
<a name="line661"></a>    while (node = node[pSibling]) {
<a name="line662"></a>      if (simpleNodeTest(node)) {
<a name="line663"></a>        return false;
<a name="line664"></a>      }
<a name="line665"></a>    }
<a name="line666"></a>    return true;
<a name="line667"></a>  };
<a name="line668"></a>
<a name="line669"></a>  var _lookRight = function(node) {
<a name="line670"></a>    while (node = node[nSibling]) {
<a name="line671"></a>      if (simpleNodeTest(node)) {
<a name="line672"></a>        return false;
<a name="line673"></a>      }
<a name="line674"></a>    }
<a name="line675"></a>    return true;
<a name="line676"></a>  };
<a name="line677"></a>
<a name="line678"></a>  var getNodeIndex = function(node) {
<a name="line679"></a>    var root = node.parentNode;
<a name="line680"></a>    var i = 0,
<a name="line681"></a>        tret = root[childNodesName],
<a name="line682"></a>        ci = (node[&#39;_i&#39;] || -1),
<a name="line683"></a>        cl = (root[&#39;_l&#39;] || -1);
<a name="line684"></a>
<a name="line685"></a>    if (!tret) {
<a name="line686"></a>      return -1;
<a name="line687"></a>    }
<a name="line688"></a>    var l = tret.length;
<a name="line689"></a>
<a name="line690"></a>    // we calculate the parent length as a cheap way to invalidate the
<a name="line691"></a>    // cache. It&#39;s not 100% accurate, but it&#39;s much more honest than what
<a name="line692"></a>    // other libraries do
<a name="line693"></a>    if (cl == l &amp;&amp; ci &gt;= 0 &amp;&amp; cl &gt;= 0) {
<a name="line694"></a>      // if it&#39;s legit, tag and release
<a name="line695"></a>      return ci;
<a name="line696"></a>    }
<a name="line697"></a>
<a name="line698"></a>    // else re-key things
<a name="line699"></a>    root[&#39;_l&#39;] = l;
<a name="line700"></a>    ci = -1;
<a name="line701"></a>    var te = root[&#39;firstElementChild&#39;] || root[&#39;firstChild&#39;];
<a name="line702"></a>    for (; te; te = te[nSibling]) {
<a name="line703"></a>      if (simpleNodeTest(te)) {
<a name="line704"></a>        te[&#39;_i&#39;] = ++i;
<a name="line705"></a>        if (node === te) {
<a name="line706"></a>          // NOTE:
<a name="line707"></a>          //  shortcutting the return at this step in indexing works
<a name="line708"></a>          //  very well for benchmarking but we avoid it here since
<a name="line709"></a>          //  it leads to potential O(n^2) behavior in sequential
<a name="line710"></a>          //  getNodexIndex operations on a previously un-indexed
<a name="line711"></a>          //  parent. We may revisit this at a later time, but for
<a name="line712"></a>          //  now we just want to get the right answer more often
<a name="line713"></a>          //  than not.
<a name="line714"></a>          ci = i;
<a name="line715"></a>        }
<a name="line716"></a>      }
<a name="line717"></a>    }
<a name="line718"></a>    return ci;
<a name="line719"></a>  };
<a name="line720"></a>
<a name="line721"></a>  var isEven = function(elem) {
<a name="line722"></a>    return !((getNodeIndex(elem)) % 2);
<a name="line723"></a>  };
<a name="line724"></a>
<a name="line725"></a>  var isOdd = function(elem) {
<a name="line726"></a>    return (getNodeIndex(elem)) % 2;
<a name="line727"></a>  };
<a name="line728"></a>
<a name="line729"></a>  var pseudos = {
<a name="line730"></a>    &#39;checked&#39;: function(name, condition) {
<a name="line731"></a>      return function(elem) {
<a name="line732"></a>        return elem.checked || elem.attributes[&#39;checked&#39;];
<a name="line733"></a>      }
<a name="line734"></a>    },
<a name="line735"></a>    &#39;first-child&#39;: function() {
<a name="line736"></a>      return _lookLeft;
<a name="line737"></a>    },
<a name="line738"></a>    &#39;last-child&#39;: function() {
<a name="line739"></a>      return _lookRight;
<a name="line740"></a>    },
<a name="line741"></a>    &#39;only-child&#39;: function(name, condition) {
<a name="line742"></a>      return function(node) {
<a name="line743"></a>        if (!_lookLeft(node)) {
<a name="line744"></a>          return false;
<a name="line745"></a>        }
<a name="line746"></a>        if (!_lookRight(node)) {
<a name="line747"></a>          return false;
<a name="line748"></a>        }
<a name="line749"></a>        return true;
<a name="line750"></a>      };
<a name="line751"></a>    },
<a name="line752"></a>    &#39;empty&#39;: function(name, condition) {
<a name="line753"></a>      return function(elem) {
<a name="line754"></a>        // DomQuery and jQuery get this wrong, oddly enough.
<a name="line755"></a>        // The CSS 3 selectors spec is pretty explicit about it, too.
<a name="line756"></a>        var cn = elem.childNodes;
<a name="line757"></a>        var cnl = elem.childNodes.length;
<a name="line758"></a>        // if(!cnl) { return true; }
<a name="line759"></a>        for (var x = cnl - 1; x &gt;= 0; x--) {
<a name="line760"></a>          var nt = cn[x].nodeType;
<a name="line761"></a>          if ((nt === 1) || (nt == 3)) {
<a name="line762"></a>            return false;
<a name="line763"></a>          }
<a name="line764"></a>        }
<a name="line765"></a>        return true;
<a name="line766"></a>      }
<a name="line767"></a>    },
<a name="line768"></a>    &#39;contains&#39;: function(name, condition) {
<a name="line769"></a>      var cz = condition.charAt(0);
<a name="line770"></a>      if (cz == &#39;&quot;&#39; || cz == &quot;&#39;&quot;) { // Remove quotes.
<a name="line771"></a>        condition = condition.slice(1, -1);
<a name="line772"></a>      }
<a name="line773"></a>      return function(elem) {
<a name="line774"></a>        return (elem.innerHTML.indexOf(condition) &gt;= 0);
<a name="line775"></a>      }
<a name="line776"></a>    },
<a name="line777"></a>    &#39;not&#39;: function(name, condition) {
<a name="line778"></a>      var p = getQueryParts(condition)[0];
<a name="line779"></a>      var ignores = { el: 1 };
<a name="line780"></a>      if (p.tag != &#39;*&#39;) {
<a name="line781"></a>        ignores.tag = 1;
<a name="line782"></a>      }
<a name="line783"></a>      if (!p.classes.length) {
<a name="line784"></a>        ignores.classes = 1;
<a name="line785"></a>      }
<a name="line786"></a>      var ntf = getSimpleFilterFunc(p, ignores);
<a name="line787"></a>      return function(elem) {
<a name="line788"></a>        return !ntf(elem);
<a name="line789"></a>      }
<a name="line790"></a>    },
<a name="line791"></a>    &#39;nth-child&#39;: function(name, condition) {
<a name="line792"></a>      function pi(n) {
<a name="line793"></a>        return parseInt(n, 10);
<a name="line794"></a>      }
<a name="line795"></a>      // avoid re-defining function objects if we can
<a name="line796"></a>      if (condition == &#39;odd&#39;) {
<a name="line797"></a>        return isOdd;
<a name="line798"></a>      } else if (condition == &#39;even&#39;) {
<a name="line799"></a>        return isEven;
<a name="line800"></a>      }
<a name="line801"></a>      // FIXME: can we shorten this?
<a name="line802"></a>      if (condition.indexOf(&#39;n&#39;) != -1) {
<a name="line803"></a>        var tparts = condition.split(&#39;n&#39;, 2);
<a name="line804"></a>        var pred = tparts[0] ? ((tparts[0] == &#39;-&#39;) ? -1 : pi(tparts[0])) : 1;
<a name="line805"></a>        var idx = tparts[1] ? pi(tparts[1]) : 0;
<a name="line806"></a>        var lb = 0, ub = -1;
<a name="line807"></a>        if (pred &gt; 0) {
<a name="line808"></a>          if (idx &lt; 0) {
<a name="line809"></a>            idx = (idx % pred) &amp;&amp; (pred + (idx % pred));
<a name="line810"></a>          } else if (idx &gt; 0) {
<a name="line811"></a>            if (idx &gt;= pred) {
<a name="line812"></a>              lb = idx - idx % pred;
<a name="line813"></a>            }
<a name="line814"></a>            idx = idx % pred;
<a name="line815"></a>          }
<a name="line816"></a>        } else if (pred &lt; 0) {
<a name="line817"></a>          pred *= -1;
<a name="line818"></a>          // idx has to be greater than 0 when pred is negative;
<a name="line819"></a>          // shall we throw an error here?
<a name="line820"></a>          if (idx &gt; 0) {
<a name="line821"></a>            ub = idx;
<a name="line822"></a>            idx = idx % pred;
<a name="line823"></a>          }
<a name="line824"></a>        }
<a name="line825"></a>        if (pred &gt; 0) {
<a name="line826"></a>          return function(elem) {
<a name="line827"></a>            var i = getNodeIndex(elem);
<a name="line828"></a>            return (i &gt;= lb) &amp;&amp; (ub &lt; 0 || i &lt;= ub) &amp;&amp; ((i % pred) == idx);
<a name="line829"></a>          }
<a name="line830"></a>        } else {
<a name="line831"></a>          condition = idx;
<a name="line832"></a>        }
<a name="line833"></a>      }
<a name="line834"></a>      var ncount = pi(condition);
<a name="line835"></a>      return function(elem) {
<a name="line836"></a>        return (getNodeIndex(elem) == ncount);
<a name="line837"></a>      }
<a name="line838"></a>    }
<a name="line839"></a>  };
<a name="line840"></a>
<a name="line841"></a>  var defaultGetter = (goog.userAgent.IE) ? function(cond) {
<a name="line842"></a>    var clc = cond.toLowerCase();
<a name="line843"></a>    if (clc == &#39;class&#39;) {
<a name="line844"></a>      cond = &#39;className&#39;;
<a name="line845"></a>    }
<a name="line846"></a>    return function(elem) {
<a name="line847"></a>      return caseSensitive ? elem.getAttribute(cond) : elem[cond] || elem[clc];
<a name="line848"></a>    }
<a name="line849"></a>  } : function(cond) {
<a name="line850"></a>    return function(elem) {
<a name="line851"></a>      return elem &amp;&amp; elem.getAttribute &amp;&amp; elem.hasAttribute(cond);
<a name="line852"></a>    }
<a name="line853"></a>  };
<a name="line854"></a>
<a name="line855"></a>  var getSimpleFilterFunc = function(query, ignores) {
<a name="line856"></a>    // Generates a node tester function based on the passed query part. The
<a name="line857"></a>    // query part is one of the structures generated by the query parser when it
<a name="line858"></a>    // creates the query AST. The &#39;ignores&#39; object specifies which (if any)
<a name="line859"></a>    // tests to skip, allowing the system to avoid duplicating work where it
<a name="line860"></a>    // may have already been taken into account by other factors such as how
<a name="line861"></a>    // the nodes to test were fetched in the first place.
<a name="line862"></a>    if (!query) {
<a name="line863"></a>      return goog.functions.TRUE;
<a name="line864"></a>    }
<a name="line865"></a>    ignores = ignores || {};
<a name="line866"></a>
<a name="line867"></a>    var ff = null;
<a name="line868"></a>
<a name="line869"></a>    if (!ignores.el) {
<a name="line870"></a>      ff = agree(ff, isElement);
<a name="line871"></a>    }
<a name="line872"></a>
<a name="line873"></a>    if (!ignores.tag) {
<a name="line874"></a>      if (query.tag != &#39;*&#39;) {
<a name="line875"></a>        ff = agree(ff, function(elem) {
<a name="line876"></a>          return (elem &amp;&amp; (elem.tagName == query.getTag()));
<a name="line877"></a>        });
<a name="line878"></a>      }
<a name="line879"></a>    }
<a name="line880"></a>
<a name="line881"></a>    if (!ignores.classes) {
<a name="line882"></a>      goog.array.forEach(query.classes, function(cname, idx, arr) {
<a name="line883"></a>        // Get the class name.
<a name="line884"></a>        var re = new RegExp(&#39;(?:^|\\s)&#39; + cname + &#39;(?:\\s|$)&#39;);
<a name="line885"></a>        ff = agree(ff, function(elem) {
<a name="line886"></a>          return re.test(elem.className);
<a name="line887"></a>        });
<a name="line888"></a>        ff.count = idx;
<a name="line889"></a>      });
<a name="line890"></a>    }
<a name="line891"></a>
<a name="line892"></a>    if (!ignores.pseudos) {
<a name="line893"></a>      goog.array.forEach(query.pseudos, function(pseudo) {
<a name="line894"></a>        var pn = pseudo.name;
<a name="line895"></a>        if (pseudos[pn]) {
<a name="line896"></a>          ff = agree(ff, pseudos[pn](pn, pseudo.value));
<a name="line897"></a>        }
<a name="line898"></a>      });
<a name="line899"></a>    }
<a name="line900"></a>
<a name="line901"></a>    if (!ignores.attrs) {
<a name="line902"></a>      goog.array.forEach(query.attrs, function(attr) {
<a name="line903"></a>        var matcher;
<a name="line904"></a>        var a = attr.attr;
<a name="line905"></a>        // type, attr, matchFor
<a name="line906"></a>        if (attr.type &amp;&amp; attrs[attr.type]) {
<a name="line907"></a>          matcher = attrs[attr.type](a, attr.matchFor);
<a name="line908"></a>        } else if (a.length) {
<a name="line909"></a>          matcher = defaultGetter(a);
<a name="line910"></a>        }
<a name="line911"></a>        if (matcher) {
<a name="line912"></a>          ff = agree(ff, matcher);
<a name="line913"></a>        }
<a name="line914"></a>      });
<a name="line915"></a>    }
<a name="line916"></a>
<a name="line917"></a>    if (!ignores.id) {
<a name="line918"></a>      if (query.id) {
<a name="line919"></a>        ff = agree(ff, function(elem) {
<a name="line920"></a>          return (!!elem &amp;&amp; (elem.id == query.id));
<a name="line921"></a>        });
<a name="line922"></a>      }
<a name="line923"></a>    }
<a name="line924"></a>
<a name="line925"></a>    if (!ff) {
<a name="line926"></a>      if (!(&#39;default&#39; in ignores)) {
<a name="line927"></a>        ff = goog.functions.TRUE;
<a name="line928"></a>      }
<a name="line929"></a>    }
<a name="line930"></a>    return ff;
<a name="line931"></a>  };
<a name="line932"></a>
<a name="line933"></a>  var nextSiblingIterator = function(filterFunc) {
<a name="line934"></a>    return function(node, ret, bag) {
<a name="line935"></a>      while (node = node[nSibling]) {
<a name="line936"></a>        if (noNextElementSibling &amp;&amp; (!isElement(node))) {
<a name="line937"></a>          continue;
<a name="line938"></a>        }
<a name="line939"></a>        if (
<a name="line940"></a>          (!bag || _isUnique(node, bag)) &amp;&amp;
<a name="line941"></a>          filterFunc(node)
<a name="line942"></a>        ) {
<a name="line943"></a>          ret.push(node);
<a name="line944"></a>        }
<a name="line945"></a>        break;
<a name="line946"></a>      }
<a name="line947"></a>      return ret;
<a name="line948"></a>    };
<a name="line949"></a>  };
<a name="line950"></a>
<a name="line951"></a>  var nextSiblingsIterator = function(filterFunc) {
<a name="line952"></a>    return function(root, ret, bag) {
<a name="line953"></a>      var te = root[nSibling];
<a name="line954"></a>      while (te) {
<a name="line955"></a>        if (simpleNodeTest(te)) {
<a name="line956"></a>          if (bag &amp;&amp; !_isUnique(te, bag)) {
<a name="line957"></a>            break;
<a name="line958"></a>          }
<a name="line959"></a>          if (filterFunc(te)) {
<a name="line960"></a>            ret.push(te);
<a name="line961"></a>          }
<a name="line962"></a>        }
<a name="line963"></a>        te = te[nSibling];
<a name="line964"></a>      }
<a name="line965"></a>      return ret;
<a name="line966"></a>    };
<a name="line967"></a>  };
<a name="line968"></a>
<a name="line969"></a>  // Get an array of child *elements*, skipping text and comment nodes
<a name="line970"></a>  var _childElements = function(filterFunc) {
<a name="line971"></a>    filterFunc = filterFunc || goog.functions.TRUE;
<a name="line972"></a>    return function(root, ret, bag) {
<a name="line973"></a>      var te, x = 0, tret = root[childNodesName];
<a name="line974"></a>      while (te = tret[x++]) {
<a name="line975"></a>        if (
<a name="line976"></a>          simpleNodeTest(te) &amp;&amp;
<a name="line977"></a>          (!bag || _isUnique(te, bag)) &amp;&amp;
<a name="line978"></a>          (filterFunc(te, x))
<a name="line979"></a>        ) {
<a name="line980"></a>          ret.push(te);
<a name="line981"></a>        }
<a name="line982"></a>      }
<a name="line983"></a>      return ret;
<a name="line984"></a>    };
<a name="line985"></a>  };
<a name="line986"></a>
<a name="line987"></a>  // test to see if node is below root
<a name="line988"></a>  var _isDescendant = function(node, root) {
<a name="line989"></a>    var pn = node.parentNode;
<a name="line990"></a>    while (pn) {
<a name="line991"></a>      if (pn == root) {
<a name="line992"></a>        break;
<a name="line993"></a>      }
<a name="line994"></a>      pn = pn.parentNode;
<a name="line995"></a>    }
<a name="line996"></a>    return !!pn;
<a name="line997"></a>  };
<a name="line998"></a>
<a name="line999"></a>  var _getElementsFuncCache = {};
<a name="line1000"></a>
<a name="line1001"></a>  var getElementsFunc = function(query) {
<a name="line1002"></a>    var retFunc = _getElementsFuncCache[query.query];
<a name="line1003"></a>    // If we&#39;ve got a cached dispatcher, just use that.
<a name="line1004"></a>    if (retFunc) {
<a name="line1005"></a>      return retFunc;
<a name="line1006"></a>    }
<a name="line1007"></a>    // Else, generate a new one.
<a name="line1008"></a>
<a name="line1009"></a>    // NOTE:
<a name="line1010"></a>    //    This function returns a function that searches for nodes and
<a name="line1011"></a>    //    filters them. The search may be specialized by infix operators
<a name="line1012"></a>    //    (&quot;&gt;&quot;, &quot;~&quot;, or &quot;+&quot;) else it will default to searching all
<a name="line1013"></a>    //    descendants (the &quot; &quot; selector). Once a group of children is
<a name="line1014"></a>    //    found, a test function is applied to weed out the ones we
<a name="line1015"></a>    //    don&#39;t want. Many common cases can be fast-pathed. We spend a
<a name="line1016"></a>    //    lot of cycles to create a dispatcher that doesn&#39;t do more work
<a name="line1017"></a>    //    than necessary at any point since, unlike this function, the
<a name="line1018"></a>    //    dispatchers will be called every time. The logic of generating
<a name="line1019"></a>    //    efficient dispatchers looks like this in pseudo code:
<a name="line1020"></a>    //
<a name="line1021"></a>    //    # if it&#39;s a purely descendant query (no &quot;&gt;&quot;, &quot;+&quot;, or &quot;~&quot; modifiers)
<a name="line1022"></a>    //    if infixOperator == &quot; &quot;:
<a name="line1023"></a>    //      if only(id):
<a name="line1024"></a>    //        return def(root):
<a name="line1025"></a>    //          return d.byId(id, root);
<a name="line1026"></a>    //
<a name="line1027"></a>    //      elif id:
<a name="line1028"></a>    //        return def(root):
<a name="line1029"></a>    //          return filter(d.byId(id, root));
<a name="line1030"></a>    //
<a name="line1031"></a>    //      elif cssClass &amp;&amp; getElementsByClassName:
<a name="line1032"></a>    //        return def(root):
<a name="line1033"></a>    //          return filter(root.getElementsByClassName(cssClass));
<a name="line1034"></a>    //
<a name="line1035"></a>    //      elif only(tag):
<a name="line1036"></a>    //        return def(root):
<a name="line1037"></a>    //          return root.getElementsByTagName(tagName);
<a name="line1038"></a>    //
<a name="line1039"></a>    //      else:
<a name="line1040"></a>    //        # search by tag name, then filter
<a name="line1041"></a>    //        return def(root):
<a name="line1042"></a>    //          return filter(root.getElementsByTagName(tagName||&quot;*&quot;));
<a name="line1043"></a>    //
<a name="line1044"></a>    //    elif infixOperator == &quot;&gt;&quot;:
<a name="line1045"></a>    //      # search direct children
<a name="line1046"></a>    //      return def(root):
<a name="line1047"></a>    //        return filter(root.children);
<a name="line1048"></a>    //
<a name="line1049"></a>    //    elif infixOperator == &quot;+&quot;:
<a name="line1050"></a>    //      # search next sibling
<a name="line1051"></a>    //      return def(root):
<a name="line1052"></a>    //        return filter(root.nextElementSibling);
<a name="line1053"></a>    //
<a name="line1054"></a>    //    elif infixOperator == &quot;~&quot;:
<a name="line1055"></a>    //      # search rightward siblings
<a name="line1056"></a>    //      return def(root):
<a name="line1057"></a>    //        return filter(nextSiblings(root));
<a name="line1058"></a>
<a name="line1059"></a>    var io = query.infixOper;
<a name="line1060"></a>    var oper = (io ? io.oper : &#39;&#39;);
<a name="line1061"></a>    // The default filter func which tests for all conditions in the query
<a name="line1062"></a>    // part. This is potentially inefficient, so some optimized paths may
<a name="line1063"></a>    // re-define it to test fewer things.
<a name="line1064"></a>    var filterFunc = getSimpleFilterFunc(query, { el: 1 });
<a name="line1065"></a>    var qt = query.tag;
<a name="line1066"></a>    var wildcardTag = (&#39;*&#39; == qt);
<a name="line1067"></a>    var ecs = goog.dom.getDocument()[&#39;getElementsByClassName&#39;];
<a name="line1068"></a>
<a name="line1069"></a>    if (!oper) {
<a name="line1070"></a>      // If there&#39;s no infix operator, then it&#39;s a descendant query. ID
<a name="line1071"></a>      // and &quot;elements by class name&quot; variants can be accelerated so we
<a name="line1072"></a>      // call them out explicitly:
<a name="line1073"></a>      if (query.id) {
<a name="line1074"></a>        // Testing shows that the overhead of goog.functions.TRUE() is
<a name="line1075"></a>        // acceptable and can save us some bytes vs. re-defining the function
<a name="line1076"></a>        // everywhere.
<a name="line1077"></a>        filterFunc = (!query.loops &amp;&amp; wildcardTag) ?
<a name="line1078"></a>          goog.functions.TRUE :
<a name="line1079"></a>          getSimpleFilterFunc(query, { el: 1, id: 1 });
<a name="line1080"></a>
<a name="line1081"></a>        retFunc = function(root, arr) {
<a name="line1082"></a>          var te = goog.dom.getDomHelper(root).getElement(query.id);
<a name="line1083"></a>          if (!te || !filterFunc(te)) {
<a name="line1084"></a>            return;
<a name="line1085"></a>          }
<a name="line1086"></a>          if (9 == root.nodeType) { // If root&#39;s a doc, we just return directly.
<a name="line1087"></a>            return getArr(te, arr);
<a name="line1088"></a>          } else { // otherwise check ancestry
<a name="line1089"></a>            if (_isDescendant(te, root)) {
<a name="line1090"></a>              return getArr(te, arr);
<a name="line1091"></a>            }
<a name="line1092"></a>          }
<a name="line1093"></a>        }
<a name="line1094"></a>      } else if (
<a name="line1095"></a>        ecs &amp;&amp;
<a name="line1096"></a>        // isAlien check. Workaround for Prototype.js being totally evil/dumb.
<a name="line1097"></a>        /\{\s*\[native code\]\s*\}/.test(String(ecs)) &amp;&amp;
<a name="line1098"></a>        query.classes.length &amp;&amp;
<a name="line1099"></a>        // WebKit bug where quirks-mode docs select by class w/o case
<a name="line1100"></a>        // sensitivity.
<a name="line1101"></a>        !cssCaseBug
<a name="line1102"></a>      ) {
<a name="line1103"></a>        // it&#39;s a class-based query and we&#39;ve got a fast way to run it.
<a name="line1104"></a>
<a name="line1105"></a>        // ignore class and ID filters since we will have handled both
<a name="line1106"></a>        filterFunc = getSimpleFilterFunc(query, { el: 1, classes: 1, id: 1 });
<a name="line1107"></a>        var classesString = query.classes.join(&#39; &#39;);
<a name="line1108"></a>        retFunc = function(root, arr) {
<a name="line1109"></a>          var ret = getArr(0, arr), te, x = 0;
<a name="line1110"></a>          var tret = root.getElementsByClassName(classesString);
<a name="line1111"></a>          while ((te = tret[x++])) {
<a name="line1112"></a>            if (filterFunc(te, root)) {
<a name="line1113"></a>              ret.push(te);
<a name="line1114"></a>            }
<a name="line1115"></a>          }
<a name="line1116"></a>          return ret;
<a name="line1117"></a>        };
<a name="line1118"></a>
<a name="line1119"></a>      } else if (!wildcardTag &amp;&amp; !query.loops) {
<a name="line1120"></a>        // it&#39;s tag only. Fast-path it.
<a name="line1121"></a>        retFunc = function(root, arr) {
<a name="line1122"></a>          var ret = getArr(0, arr), te, x = 0;
<a name="line1123"></a>          var tret = root.getElementsByTagName(query.getTag());
<a name="line1124"></a>          while ((te = tret[x++])) {
<a name="line1125"></a>            ret.push(te);
<a name="line1126"></a>          }
<a name="line1127"></a>          return ret;
<a name="line1128"></a>        };
<a name="line1129"></a>      } else {
<a name="line1130"></a>        // the common case:
<a name="line1131"></a>        //    a descendant selector without a fast path. By now it&#39;s got
<a name="line1132"></a>        //    to have a tag selector, even if it&#39;s just &quot;*&quot; so we query
<a name="line1133"></a>        //    by that and filter
<a name="line1134"></a>        filterFunc = getSimpleFilterFunc(query, { el: 1, tag: 1, id: 1 });
<a name="line1135"></a>        retFunc = function(root, arr) {
<a name="line1136"></a>          var ret = getArr(0, arr), te, x = 0;
<a name="line1137"></a>          // we use getTag() to avoid case sensitivity issues
<a name="line1138"></a>          var tret = root.getElementsByTagName(query.getTag());
<a name="line1139"></a>          while (te = tret[x++]) {
<a name="line1140"></a>            if (filterFunc(te, root)) {
<a name="line1141"></a>              ret.push(te);
<a name="line1142"></a>            }
<a name="line1143"></a>          }
<a name="line1144"></a>          return ret;
<a name="line1145"></a>        };
<a name="line1146"></a>      }
<a name="line1147"></a>    } else {
<a name="line1148"></a>      // the query is scoped in some way. Instead of querying by tag we
<a name="line1149"></a>      // use some other collection to find candidate nodes
<a name="line1150"></a>      var skipFilters = { el: 1 };
<a name="line1151"></a>      if (wildcardTag) {
<a name="line1152"></a>        skipFilters.tag = 1;
<a name="line1153"></a>      }
<a name="line1154"></a>      filterFunc = getSimpleFilterFunc(query, skipFilters);
<a name="line1155"></a>      if (&#39;+&#39; == oper) {
<a name="line1156"></a>        retFunc = nextSiblingIterator(filterFunc);
<a name="line1157"></a>      } else if (&#39;~&#39; == oper) {
<a name="line1158"></a>        retFunc = nextSiblingsIterator(filterFunc);
<a name="line1159"></a>      } else if (&#39;&gt;&#39; == oper) {
<a name="line1160"></a>        retFunc = _childElements(filterFunc);
<a name="line1161"></a>      }
<a name="line1162"></a>    }
<a name="line1163"></a>    // cache it and return
<a name="line1164"></a>    return _getElementsFuncCache[query.query] = retFunc;
<a name="line1165"></a>  };
<a name="line1166"></a>
<a name="line1167"></a>  var filterDown = function(root, queryParts) {
<a name="line1168"></a>    // NOTE:
<a name="line1169"></a>    //    this is the guts of the DOM query system. It takes a list of
<a name="line1170"></a>    //    parsed query parts and a root and finds children which match
<a name="line1171"></a>    //    the selector represented by the parts
<a name="line1172"></a>    var candidates = getArr(root), qp, x, te, qpl = queryParts.length, bag, ret;
<a name="line1173"></a>
<a name="line1174"></a>    for (var i = 0; i &lt; qpl; i++) {
<a name="line1175"></a>      ret = [];
<a name="line1176"></a>      qp = queryParts[i];
<a name="line1177"></a>      x = candidates.length - 1;
<a name="line1178"></a>      if (x &gt; 0) {
<a name="line1179"></a>        // if we have more than one root at this level, provide a new
<a name="line1180"></a>        // hash to use for checking group membership but tell the
<a name="line1181"></a>        // system not to post-filter us since we will already have been
<a name="line1182"></a>        // guaranteed to be unique
<a name="line1183"></a>        bag = {};
<a name="line1184"></a>        ret.nozip = true;
<a name="line1185"></a>      }
<a name="line1186"></a>      var gef = getElementsFunc(qp);
<a name="line1187"></a>      for (var j = 0; te = candidates[j]; j++) {
<a name="line1188"></a>        // for every root, get the elements that match the descendant
<a name="line1189"></a>        // selector, adding them to the &#39;ret&#39; array and filtering them
<a name="line1190"></a>        // via membership in this level&#39;s bag. If there are more query
<a name="line1191"></a>        // parts, then this level&#39;s return will be used as the next
<a name="line1192"></a>        // level&#39;s candidates
<a name="line1193"></a>        gef(te, ret, bag);
<a name="line1194"></a>      }
<a name="line1195"></a>      if (!ret.length) { break; }
<a name="line1196"></a>      candidates = ret;
<a name="line1197"></a>    }
<a name="line1198"></a>    return ret;
<a name="line1199"></a>  };
<a name="line1200"></a>
<a name="line1201"></a>  ////////////////////////////////////////////////////////////////////////
<a name="line1202"></a>  // the query runner
<a name="line1203"></a>  ////////////////////////////////////////////////////////////////////////
<a name="line1204"></a>
<a name="line1205"></a>  // these are the primary caches for full-query results. The query
<a name="line1206"></a>  // dispatcher functions are generated then stored here for hash lookup in
<a name="line1207"></a>  // the future
<a name="line1208"></a>  var _queryFuncCacheDOM = {},
<a name="line1209"></a>    _queryFuncCacheQSA = {};
<a name="line1210"></a>
<a name="line1211"></a>  // this is the second level of splitting, from full-length queries (e.g.,
<a name="line1212"></a>  // &#39;div.foo .bar&#39;) into simple query expressions (e.g., [&#39;div.foo&#39;,
<a name="line1213"></a>  // &#39;.bar&#39;])
<a name="line1214"></a>  var getStepQueryFunc = function(query) {
<a name="line1215"></a>    var qparts = getQueryParts(goog.string.trim(query));
<a name="line1216"></a>
<a name="line1217"></a>    // if it&#39;s trivial, avoid iteration and zipping costs
<a name="line1218"></a>    if (qparts.length == 1) {
<a name="line1219"></a>      // We optimize this case here to prevent dispatch further down the
<a name="line1220"></a>      // chain, potentially slowing things down. We could more elegantly
<a name="line1221"></a>      // handle this in filterDown(), but it&#39;s slower for simple things
<a name="line1222"></a>      // that need to be fast (e.g., &#39;#someId&#39;).
<a name="line1223"></a>      var tef = getElementsFunc(qparts[0]);
<a name="line1224"></a>      return function(root) {
<a name="line1225"></a>        var r = tef(root, []);
<a name="line1226"></a>        if (r) { r.nozip = true; }
<a name="line1227"></a>        return r;
<a name="line1228"></a>      }
<a name="line1229"></a>    }
<a name="line1230"></a>
<a name="line1231"></a>    // otherwise, break it up and return a runner that iterates over the parts
<a name="line1232"></a>    // recursively
<a name="line1233"></a>    return function(root) {
<a name="line1234"></a>      return filterDown(root, qparts);
<a name="line1235"></a>    }
<a name="line1236"></a>  };
<a name="line1237"></a>
<a name="line1238"></a>  // NOTES:
<a name="line1239"></a>  //  * we can&#39;t trust QSA for anything but document-rooted queries, so
<a name="line1240"></a>  //    caching is split into DOM query evaluators and QSA query evaluators
<a name="line1241"></a>  //  * caching query results is dirty and leak-prone (or, at a minimum,
<a name="line1242"></a>  //    prone to unbounded growth). Other toolkits may go this route, but
<a name="line1243"></a>  //    they totally destroy their own ability to manage their memory
<a name="line1244"></a>  //    footprint. If we implement it, it should only ever be with a fixed
<a name="line1245"></a>  //    total element reference # limit and an LRU-style algorithm since JS
<a name="line1246"></a>  //    has no weakref support. Caching compiled query evaluators is also
<a name="line1247"></a>  //    potentially problematic, but even on large documents the size of the
<a name="line1248"></a>  //    query evaluators is often &lt; 100 function objects per evaluator (and
<a name="line1249"></a>  //    LRU can be applied if it&#39;s ever shown to be an issue).
<a name="line1250"></a>  //  * since IE&#39;s QSA support is currently only for HTML documents and even
<a name="line1251"></a>  //    then only in IE 8&#39;s &#39;standards mode&#39;, we have to detect our dispatch
<a name="line1252"></a>  //    route at query time and keep 2 separate caches. Ugg.
<a name="line1253"></a>
<a name="line1254"></a>  var qsa = &#39;querySelectorAll&#39;;
<a name="line1255"></a>
<a name="line1256"></a>  // some versions of Safari provided QSA, but it was buggy and crash-prone.
<a name="line1257"></a>  // We need to detect the right &#39;internal&#39; webkit version to make this work.
<a name="line1258"></a>  var qsaAvail = (
<a name="line1259"></a>    !!goog.dom.getDocument()[qsa] &amp;&amp;
<a name="line1260"></a>    // see #5832
<a name="line1261"></a>    (!goog.userAgent.WEBKIT || goog.userAgent.isVersion(&#39;526&#39;))
<a name="line1262"></a>  );
<a name="line1263"></a>
<a name="line1264"></a>  /** @param {boolean=} opt_forceDOM */
<a name="line1265"></a>  var getQueryFunc = function(query, opt_forceDOM) {
<a name="line1266"></a>
<a name="line1267"></a>    if (qsaAvail) {
<a name="line1268"></a>      // if we&#39;ve got a cached variant and we think we can do it, run it!
<a name="line1269"></a>      var qsaCached = _queryFuncCacheQSA[query];
<a name="line1270"></a>      if (qsaCached &amp;&amp; !opt_forceDOM) {
<a name="line1271"></a>        return qsaCached;
<a name="line1272"></a>      }
<a name="line1273"></a>    }
<a name="line1274"></a>
<a name="line1275"></a>    // else if we&#39;ve got a DOM cached variant, assume that we already know
<a name="line1276"></a>    // all we need to and use it
<a name="line1277"></a>    var domCached = _queryFuncCacheDOM[query];
<a name="line1278"></a>    if (domCached) {
<a name="line1279"></a>      return domCached;
<a name="line1280"></a>    }
<a name="line1281"></a>
<a name="line1282"></a>    // TODO:
<a name="line1283"></a>    //    today we&#39;re caching DOM and QSA branches separately so we
<a name="line1284"></a>    //    recalc useQSA every time. If we had a way to tag root+query
<a name="line1285"></a>    //    efficiently, we&#39;d be in good shape to do a global cache.
<a name="line1286"></a>
<a name="line1287"></a>    var qcz = query.charAt(0);
<a name="line1288"></a>    var nospace = (-1 == query.indexOf(&#39; &#39;));
<a name="line1289"></a>
<a name="line1290"></a>    // byId searches are wicked fast compared to QSA, even when filtering
<a name="line1291"></a>    // is required
<a name="line1292"></a>    if ((query.indexOf(&#39;#&#39;) &gt;= 0) &amp;&amp; (nospace)) {
<a name="line1293"></a>      opt_forceDOM = true;
<a name="line1294"></a>    }
<a name="line1295"></a>
<a name="line1296"></a>    var useQSA = (
<a name="line1297"></a>      qsaAvail &amp;&amp; (!opt_forceDOM) &amp;&amp;
<a name="line1298"></a>      // as per CSS 3, we can&#39;t currently start w/ combinator:
<a name="line1299"></a>      //    http://www.w3.org/TR/css3-selectors/#w3cselgrammar
<a name="line1300"></a>      (specials.indexOf(qcz) == -1) &amp;&amp;
<a name="line1301"></a>      // IE&#39;s QSA impl sucks on pseudos
<a name="line1302"></a>      (!goog.userAgent.IE || (query.indexOf(&#39;:&#39;) == -1)) &amp;&amp;
<a name="line1303"></a>
<a name="line1304"></a>      (!(cssCaseBug &amp;&amp; (query.indexOf(&#39;.&#39;) &gt;= 0))) &amp;&amp;
<a name="line1305"></a>
<a name="line1306"></a>      // FIXME:
<a name="line1307"></a>      //    need to tighten up browser rules on &#39;:contains&#39; and &#39;|=&#39; to
<a name="line1308"></a>      //    figure out which aren&#39;t good
<a name="line1309"></a>      (query.indexOf(&#39;:contains&#39;) == -1) &amp;&amp;
<a name="line1310"></a>      (query.indexOf(&#39;|=&#39;) == -1) // some browsers don&#39;t understand it
<a name="line1311"></a>    );
<a name="line1312"></a>
<a name="line1313"></a>    // TODO:
<a name="line1314"></a>    //    if we&#39;ve got a descendant query (e.g., &#39;&gt; .thinger&#39; instead of
<a name="line1315"></a>    //    just &#39;.thinger&#39;) in a QSA-able doc, but are passed a child as a
<a name="line1316"></a>    //    root, it should be possible to give the item a synthetic ID and
<a name="line1317"></a>    //    trivially rewrite the query to the form &#39;#synid &gt; .thinger&#39; to
<a name="line1318"></a>    //    use the QSA branch
<a name="line1319"></a>
<a name="line1320"></a>
<a name="line1321"></a>    if (useQSA) {
<a name="line1322"></a>      var tq = (specials.indexOf(query.charAt(query.length - 1)) &gt;= 0) ?
<a name="line1323"></a>            (query + &#39; *&#39;) : query;
<a name="line1324"></a>      return _queryFuncCacheQSA[query] = function(root) {
<a name="line1325"></a>        try {
<a name="line1326"></a>          // the QSA system contains an egregious spec bug which
<a name="line1327"></a>          // limits us, effectively, to only running QSA queries over
<a name="line1328"></a>          // entire documents.  See:
<a name="line1329"></a>          //    http://ejohn.org/blog/thoughts-on-queryselectorall/
<a name="line1330"></a>          //  despite this, we can also handle QSA runs on simple
<a name="line1331"></a>          //  selectors, but we don&#39;t want detection to be expensive
<a name="line1332"></a>          //  so we&#39;re just checking for the presence of a space char
<a name="line1333"></a>          //  right now. Not elegant, but it&#39;s cheaper than running
<a name="line1334"></a>          //  the query parser when we might not need to
<a name="line1335"></a>          if (!((9 == root.nodeType) || nospace)) {
<a name="line1336"></a>            throw &#39;&#39;;
<a name="line1337"></a>          }
<a name="line1338"></a>          var r = root[qsa](tq);
<a name="line1339"></a>          // IE QSA queries may incorrectly include comment nodes, so we throw
<a name="line1340"></a>          // the zipping function into &#39;remove&#39; comments mode instead of the
<a name="line1341"></a>          // normal &#39;skip it&#39; which every other QSA-clued browser enjoys
<a name="line1342"></a>          // skip expensive duplication checks and just wrap in an array.
<a name="line1343"></a>          if (goog.userAgent.IE) {
<a name="line1344"></a>            r.commentStrip = true;
<a name="line1345"></a>          } else {
<a name="line1346"></a>            r.nozip = true;
<a name="line1347"></a>          }
<a name="line1348"></a>          return r;
<a name="line1349"></a>        } catch (e) {
<a name="line1350"></a>          // else run the DOM branch on this query, ensuring that we
<a name="line1351"></a>          // default that way in the future
<a name="line1352"></a>          return getQueryFunc(query, true)(root);
<a name="line1353"></a>        }
<a name="line1354"></a>      }
<a name="line1355"></a>    } else {
<a name="line1356"></a>      // DOM branch
<a name="line1357"></a>      var parts = query.split(/\s*,\s*/);
<a name="line1358"></a>      return _queryFuncCacheDOM[query] = ((parts.length &lt; 2) ?
<a name="line1359"></a>        // if not a compound query (e.g., &#39;.foo, .bar&#39;), cache and return a
<a name="line1360"></a>        // dispatcher
<a name="line1361"></a>        getStepQueryFunc(query) :
<a name="line1362"></a>        // if it *is* a complex query, break it up into its
<a name="line1363"></a>        // constituent parts and return a dispatcher that will
<a name="line1364"></a>        // merge the parts when run
<a name="line1365"></a>        function(root) {
<a name="line1366"></a>          var pindex = 0, // avoid array alloc for every invocation
<a name="line1367"></a>            ret = [],
<a name="line1368"></a>            tp;
<a name="line1369"></a>          while (tp = parts[pindex++]) {
<a name="line1370"></a>            ret = ret.concat(getStepQueryFunc(tp)(root));
<a name="line1371"></a>          }
<a name="line1372"></a>          return ret;
<a name="line1373"></a>        }
<a name="line1374"></a>      );
<a name="line1375"></a>    }
<a name="line1376"></a>  };
<a name="line1377"></a>
<a name="line1378"></a>  var _zipIdx = 0;
<a name="line1379"></a>
<a name="line1380"></a>  // NOTE:
<a name="line1381"></a>  //    this function is Moo inspired, but our own impl to deal correctly
<a name="line1382"></a>  //    with XML in IE
<a name="line1383"></a>  var _nodeUID = goog.userAgent.IE ? function(node) {
<a name="line1384"></a>    if (caseSensitive) {
<a name="line1385"></a>      // XML docs don&#39;t have uniqueID on their nodes
<a name="line1386"></a>      return node.getAttribute(&#39;_uid&#39;) ||
<a name="line1387"></a>          node.setAttribute(&#39;_uid&#39;, ++_zipIdx) || _zipIdx;
<a name="line1388"></a>
<a name="line1389"></a>    } else {
<a name="line1390"></a>      return node.uniqueID;
<a name="line1391"></a>    }
<a name="line1392"></a>  } :
<a name="line1393"></a>  function(node) {
<a name="line1394"></a>    return (node[&#39;_uid&#39;] || (node[&#39;_uid&#39;] = ++_zipIdx));
<a name="line1395"></a>  };
<a name="line1396"></a>
<a name="line1397"></a>  // determine if a node in is unique in a &#39;bag&#39;. In this case we don&#39;t want
<a name="line1398"></a>  // to flatten a list of unique items, but rather just tell if the item in
<a name="line1399"></a>  // question is already in the bag. Normally we&#39;d just use hash lookup to do
<a name="line1400"></a>  // this for us but IE&#39;s DOM is busted so we can&#39;t really count on that. On
<a name="line1401"></a>  // the upside, it gives us a built in unique ID function.
<a name="line1402"></a>  var _isUnique = function(node, bag) {
<a name="line1403"></a>    if (!bag) {
<a name="line1404"></a>      return 1;
<a name="line1405"></a>    }
<a name="line1406"></a>    var id = _nodeUID(node);
<a name="line1407"></a>    if (!bag[id]) {
<a name="line1408"></a>      return bag[id] = 1;
<a name="line1409"></a>    }
<a name="line1410"></a>    return 0;
<a name="line1411"></a>  };
<a name="line1412"></a>
<a name="line1413"></a>  // attempt to efficiently determine if an item in a list is a dupe,
<a name="line1414"></a>  // returning a list of &#39;uniques&#39;, hopefully in document order
<a name="line1415"></a>  var _zipIdxName = &#39;_zipIdx&#39;;
<a name="line1416"></a>  var _zip = function(arr) {
<a name="line1417"></a>    if (arr &amp;&amp; arr.nozip) {
<a name="line1418"></a>      return arr;
<a name="line1419"></a>    }
<a name="line1420"></a>    var ret = [];
<a name="line1421"></a>    if (!arr || !arr.length) {
<a name="line1422"></a>      return ret;
<a name="line1423"></a>    }
<a name="line1424"></a>    if (arr[0]) {
<a name="line1425"></a>      ret.push(arr[0]);
<a name="line1426"></a>    }
<a name="line1427"></a>    if (arr.length &lt; 2) {
<a name="line1428"></a>      return ret;
<a name="line1429"></a>    }
<a name="line1430"></a>
<a name="line1431"></a>    _zipIdx++;
<a name="line1432"></a>
<a name="line1433"></a>    // we have to fork here for IE and XML docs because we can&#39;t set
<a name="line1434"></a>    // expandos on their nodes (apparently). *sigh*
<a name="line1435"></a>    if (goog.userAgent.IE &amp;&amp; caseSensitive) {
<a name="line1436"></a>      var szidx = _zipIdx + &#39;&#39;;
<a name="line1437"></a>      arr[0].setAttribute(_zipIdxName, szidx);
<a name="line1438"></a>      for (var x = 1, te; te = arr[x]; x++) {
<a name="line1439"></a>        if (arr[x].getAttribute(_zipIdxName) != szidx) {
<a name="line1440"></a>          ret.push(te);
<a name="line1441"></a>        }
<a name="line1442"></a>        te.setAttribute(_zipIdxName, szidx);
<a name="line1443"></a>      }
<a name="line1444"></a>    } else if (goog.userAgent.IE &amp;&amp; arr.commentStrip) {
<a name="line1445"></a>      try {
<a name="line1446"></a>        for (var x = 1, te; te = arr[x]; x++) {
<a name="line1447"></a>          if (isElement(te)) {
<a name="line1448"></a>            ret.push(te);
<a name="line1449"></a>          }
<a name="line1450"></a>        }
<a name="line1451"></a>      } catch (e) { /* squelch */ }
<a name="line1452"></a>    } else {
<a name="line1453"></a>      if (arr[0]) {
<a name="line1454"></a>        arr[0][_zipIdxName] = _zipIdx;
<a name="line1455"></a>      }
<a name="line1456"></a>      for (var x = 1, te; te = arr[x]; x++) {
<a name="line1457"></a>        if (arr[x][_zipIdxName] != _zipIdx) {
<a name="line1458"></a>          ret.push(te);
<a name="line1459"></a>        }
<a name="line1460"></a>        te[_zipIdxName] = _zipIdx;
<a name="line1461"></a>      }
<a name="line1462"></a>    }
<a name="line1463"></a>    return ret;
<a name="line1464"></a>  };
<a name="line1465"></a>
<a name="line1466"></a>  /**
<a name="line1467"></a>   * The main executor. Type specification from above.
<a name="line1468"></a>   * @param {string|Array} query The query.
<a name="line1469"></a>   * @param {(string|Node)=} root The root.
<a name="line1470"></a>   * @return {!Array} The elements that matched the query.
<a name="line1471"></a>   */
<a name="line1472"></a>  var query = function(query, root) {
<a name="line1473"></a>    // NOTE: elementsById is not currently supported
<a name="line1474"></a>    // NOTE: ignores xpath-ish queries for now
<a name="line1475"></a>
<a name="line1476"></a>    //Set list constructor to desired value. This can change
<a name="line1477"></a>    //between calls, so always re-assign here.
<a name="line1478"></a>
<a name="line1479"></a>    if (!query) {
<a name="line1480"></a>      return [];
<a name="line1481"></a>    }
<a name="line1482"></a>
<a name="line1483"></a>    if (query.constructor == Array) {
<a name="line1484"></a>      return /** @type {!Array} */ (query);
<a name="line1485"></a>    }
<a name="line1486"></a>
<a name="line1487"></a>    if (!goog.isString(query)) {
<a name="line1488"></a>      return [query];
<a name="line1489"></a>    }
<a name="line1490"></a>
<a name="line1491"></a>    if (goog.isString(root)) {
<a name="line1492"></a>      root = goog.dom.getElement(root);
<a name="line1493"></a>      if (!root) {
<a name="line1494"></a>        return [];
<a name="line1495"></a>      }
<a name="line1496"></a>    }
<a name="line1497"></a>
<a name="line1498"></a>    root = root || goog.dom.getDocument();
<a name="line1499"></a>    var od = root.ownerDocument || root.documentElement;
<a name="line1500"></a>
<a name="line1501"></a>    // throw the big case sensitivity switch
<a name="line1502"></a>
<a name="line1503"></a>    // NOTE:
<a name="line1504"></a>    //    Opera in XHTML mode doesn&#39;t detect case-sensitivity correctly
<a name="line1505"></a>    //    and it&#39;s not clear that there&#39;s any way to test for it
<a name="line1506"></a>    caseSensitive =
<a name="line1507"></a>        root.contentType &amp;&amp; root.contentType == &#39;application/xml&#39; ||
<a name="line1508"></a>        goog.userAgent.OPERA &amp;&amp;
<a name="line1509"></a>          (root.doctype || od.toString() == &#39;[object XMLDocument]&#39;) ||
<a name="line1510"></a>        !!od &amp;&amp;
<a name="line1511"></a>        (goog.userAgent.IE ? od.xml : (root.xmlVersion || od.xmlVersion));
<a name="line1512"></a>
<a name="line1513"></a>    // NOTE:
<a name="line1514"></a>    //    adding &#39;true&#39; as the 2nd argument to getQueryFunc is useful for
<a name="line1515"></a>    //    testing the DOM branch without worrying about the
<a name="line1516"></a>    //    behavior/performance of the QSA branch.
<a name="line1517"></a>    var r = getQueryFunc(query)(root);
<a name="line1518"></a>
<a name="line1519"></a>    // FIXME(slightlyoff):
<a name="line1520"></a>    //    need to investigate this branch WRT dojo:#8074 and dojo:#8075
<a name="line1521"></a>    if (r &amp;&amp; r.nozip) {
<a name="line1522"></a>      return r;
<a name="line1523"></a>    }
<a name="line1524"></a>    return _zip(r);
<a name="line1525"></a>  }
<a name="line1526"></a>
<a name="line1527"></a>  // FIXME: need to add infrastructure for post-filtering pseudos, ala :last
<a name="line1528"></a>  query.pseudos = pseudos;
<a name="line1529"></a>
<a name="line1530"></a>  return query;
<a name="line1531"></a>})();
<a name="line1532"></a>
<a name="line1533"></a>// TODO(arv): Please don&#39;t export here since it clobbers dead code elimination.
<a name="line1534"></a>goog.exportSymbol(&#39;goog.dom.query&#39;, goog.dom.query);
<a name="line1535"></a>goog.exportSymbol(&#39;goog.dom.query.pseudos&#39;, goog.dom.query.pseudos);
</pre>


</body>
</html>
